import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

import javax.swing.JPanel;


public class Game extends JPanel implements KeyListener, Runnable{
	
	private static final long serialVersionUID = 1486710674892307424L;
	Entity vaisseau;
	private ArrayList<Entity> explosion = new ArrayList<Entity>();
	private ArrayList<Entity> enemis = new ArrayList<Entity>();
	private ArrayList<Entity> setufo = new ArrayList<Entity>();
	private ArrayList<Entity> rockets = new ArrayList<Entity>();
	private ArrayList<Entity> lasers = new ArrayList<Entity>();
	private final int DELAY = 1;
	private Thread game;
	private double dx,dy;
	private final Set<Integer> pressed = new HashSet<Integer>();
	private Background background;
	private ArrayList<Missile> missiles_v = new ArrayList<Missile>();
	private ArrayList<Missile> missiles_e = new ArrayList<Missile>();
	int nb_m=0;
	private long time = System.currentTimeMillis();
	private Dimension resolution;
	private Rectangle screen;
	private int cpt_tirv = 0;
	private int cpt_e = 0;
	private int cpt_tire = 0;
	private int score = 0;
	private int cpt_tireufo=0;
	private int cpt_laser=0;
	
	public Game(Dimension dim) {
		
		resolution = dim;
		screen = new Rectangle(dim);
		setSize(dim.width, dim.height);
		setFocusable(true);
		addKeyListener(this);
		setBackground(Color.black);
		setDoubleBuffered(true);
		background = new Background(dim);
		vaisseau = new Vaisseau();
		vaisseau.setX((dim.width-97)/2);
		vaisseau.setY(dim.height-98);
		game = new Thread(this);
        game.start();
        
	}
	
	public void paint (Graphics g) {
		super.paint(g);
		background.draw(g);
		
		if (vaisseau != null) {
			g.setColor(Color.GREEN);
			g.fillRect(resolution.width-210, 40, vaisseau.getLife()*2, 30);
			vaisseau.draw(g);
		}
		
		for (int i=0; i < enemis.size(); i++) {
			Enemis ve = (Enemis) enemis.get(i);
			ve.draw(g);
		}
		
		for (int i=0; i < setufo.size(); i++) {
			Ufo ufo = (Ufo) setufo.get(i);
			ufo.draw(g);
		}
		
		for (int i=0; i < missiles_v.size(); i++) {
			Missile miss = missiles_v.get(i);
			miss.draw(g);
		}
		
		for (int i=0; i < lasers.size(); i++) {
			Laser laser = (Laser) lasers.get(i);
			laser.draw(g);
		}
		
		for (int i=0; i < missiles_e.size(); i++) {
			Missile miss = missiles_e.get(i);
			miss.draw(g);
		}
		
		for (int i=0; i < explosion.size(); i++) {
			if (!explosion.get(i).getFin()){
			explosion.get(i).draw(g);
			}
			else {
				explosion.remove(i);
			}
		}
		
		for (int i=0; i < rockets.size(); i++) {
			Rocket rocket = (Rocket) rockets.get(i);
			rocket.draw(g);
		}
		
		Font font = new Font("Arial", Font.PLAIN, 20);
		g.setFont(font);
		String score_str = String.valueOf(score);
		g.setColor(Color.BLUE);
		g.drawString(score_str, resolution.width-100, resolution.height-50);
	}
	
	 public void run() {

	        long beforeTime, timeDiff, sleep;

	        beforeTime = System.currentTimeMillis();

	        while (vaisseau != null) {
	        	
	        	if (time + Math.random()*2000000 < beforeTime) {
	        		
	        		if (cpt_e<Math.random()*10){
		        		Enemis ve = new Enemis();
		        		ve.setX((int) (Math.random()*(resolution.width-97)));
		        		enemis.add(ve);
		        		cpt_e+=1;
	        		}
	        		else {
	        			Ufo ufo = new Ufo();
	        			ufo.setX((int) (Math.random()*(resolution.width-128)));
	        			setufo.add(ufo);
	        			cpt_e=0;
	        		}
	        		
	        		time = beforeTime;
	        	}
	        	
	        	for (int i=0; i < enemis.size(); i++) {
	    			Enemis ve = (Enemis) enemis.get(i);
	    			ve.move();
	    			
	    			if (cpt_tire > ve.getCadence()) {
	    				Missile miss = new Missile();
		        		miss.setX(ve.getX()+47);
		    			miss.setY(ve.getY()+98);
		    			miss.setSpeed(-0.3);
		    			miss.setVect(vaisseau.getX()+47, vaisseau.getY()+48);
		    			missiles_e.add(miss);
		    			cpt_tire = 0;
	    			}
	    			cpt_tire += 1;
	    		}
	        	
	        	for (int i=0; i < setufo.size(); i++) {
	    			Ufo ufo = (Ufo) setufo.get(i);
	    			ufo.move();
	    			
	    			if (cpt_tireufo > ufo.getCadence()) {
	    				Rocket rocket = new Rocket();
		        		rocket.setX(ufo.getX()+47);
		        		rocket.setY(ufo.getY()+98);
		        		rocket.setSpeed(-0.3);
		        		rocket.setVect(vaisseau.getX()+47, vaisseau.getY()+48);
		    			rockets.add(rocket);
		    			cpt_tireufo = 0;
	    			}
	    			cpt_tireufo += 1;
	        	}
	        	
	        	
	        	if (vaisseau.getX() < 0){
	        		dx=0;
	        		vaisseau.setX(0);
	        	}
	        	
	        	if (vaisseau.getX() > screen.width-97){
	        		dx=0;
	        		vaisseau.setX(screen.width-97);
	        	}
	        	
	        	if (vaisseau.getY() < 0){
	        		dy=0;
	        		vaisseau.setY(0);
	        	}
	        	
	        	if (vaisseau.getY() > screen.height-98){
	        		dy=0;
	        		vaisseau.setY(screen.height-98);
	        	}
	        	
	        	vaisseau.move(dx,dy);
	        	
	        	if (pressed.contains(KeyEvent.VK_SPACE) && cpt_tirv > vaisseau.getCadence()) {
	    			Missile miss = new Missile();
	        		miss.setX(vaisseau.getX()+47);
	    			miss.setY(vaisseau.getY()-2);
	    			miss.setSpeed(1);
	    			missiles_v.add(miss);
	    			cpt_tirv = 0;
	        	}
	        	
	        	if (pressed.contains(KeyEvent.VK_X) && lasers.size()<1) {
	        		Laser laser = new Laser();
	        		laser.setX(vaisseau.getX()+47);
	        		laser.setY(vaisseau.getY()-50);
	        		laser.setSpeed(2);
	        		lasers.add(laser);
	        	}
	        	
	        	for (int i=0; i < missiles_v.size(); i++) {
	        		Missile miss = missiles_v.get(i);
	    			miss.move();
	    		}
	        	
	        	for (int i=0; i < lasers.size(); i++) {
	        		Laser laser = (Laser) lasers.get(i);
	    			laser.move();
	    		}
	        	
	        	for (int i=0; i < missiles_e.size(); i++) {
	        		Missile miss = missiles_e.get(i);
	    			miss.move();
	    		}
	        	
	        	for (int i=0; i < rockets.size(); i++) {
	        		Rocket rocket = (Rocket) rockets.get(i);
	        		rocket.setVect(vaisseau.getX(), vaisseau.getY());
	        		rocket.move();
	    		}
	        	
	        	collision();
	        	
	            repaint();

	            timeDiff = System.currentTimeMillis() - beforeTime;
	            sleep = DELAY - timeDiff;

	            if (sleep < 0)
	                sleep = 1;
	            try {
	                Thread.sleep(sleep);
	            } catch (InterruptedException e) {
	                System.out.println("interrupted");
	            }
	            
	            cpt_tirv += 1;
	            beforeTime = System.currentTimeMillis();
	        }
	    }

	
	private void collision() {
		
		Rectangle r3 = ((Vaisseau) vaisseau).getBounds();
		
			for (int i=0; i < missiles_v.size(); i++) {
			Missile miss = missiles_v.get(i);
			Rectangle r1 = miss.getBounds();
			
				if (!r1.intersects(screen)){
					missiles_v.remove(i);
				}
			}
			
			for (int i=0; i < lasers.size(); i++) {
				Laser laser = (Laser) lasers.get(i);
				Rectangle r1 = laser.getBounds();
				
					if (!r1.intersects(screen)){
						lasers.remove(i);
					}
					
					else {
						for (int k=0; k < enemis.size(); k++) {
							Enemis ve = (Enemis) enemis.get(k);
							Rectangle r2 = ve.getBounds();
							
							if (r1.intersects(r2) && lasers.size() > 0 && cpt_laser < 4) {
								enemis.remove(k);
								cpt_laser++;
								
								for (int l=0; l < enemis.size(); l++) {
									Enemis vel = (Enemis) enemis.get(l);
									double d = Math.pow(Math.pow(vel.getX()-laser.getX(), 2) + Math.pow(vel.getY()-laser.getY(), 2), 0.5);
									if (d < 1000) {
										laser.setVect(vel.getX(), vel.getY());
									}
								}
							}
						}
						
						if (cpt_laser == 4) {
							cpt_laser = 0;
						}
					}
					
				}
			
			for (int i=0; i < enemis.size(); i++) {
				Enemis ve = (Enemis) enemis.get(i);
				Rectangle r1 = ve.getBounds();
				
				if (r3.intersects(r1)) {
					enemis.remove(i);
					vaisseau.setLife();
					vaisseau.setLife();
					
					if (vaisseau.getLife() <= 0) {
						vaisseau = null;
					}
				}
			}
			
			for (int i=0; i < setufo.size(); i++) {
				Ufo ufo = (Ufo) setufo.get(i);
				Rectangle r1 = ufo.getBounds();
				
				if (r3.intersects(r1)) {
					setufo.remove(i);
					vaisseau.setLife();
					vaisseau.setLife();
					
					if (vaisseau.getLife() <= 0) {
						vaisseau = null;
					}
				}
			}
			
			for (int i=0; i < missiles_e.size(); i++) {
			Missile miss = missiles_e.get(i);
			Rectangle r1 = miss.getBounds();
			
				if (!r1.intersects(screen)){
					missiles_e.remove(i);
				}
				
				if (r1.intersects(r3)) {
					missiles_e.remove(i);
					vaisseau.setLife();
					
					if (vaisseau.getLife() <= 0) {
						vaisseau = null;
					}
					
				}
			}
		
			for (int i=0; i < enemis.size(); i++) {
				Enemis ve = (Enemis) enemis.get(i);
				Rectangle r1 = ve.getBounds();
				
				if (!r1.intersects(screen)){
					enemis.remove(i);
				}
				
				else {
				
					for (int j=0; j < missiles_v.size(); j++) {
						Missile miss = missiles_v.get(j);
						Rectangle r2 = miss.getBounds();
						
						if (r1.intersects(r2) && enemis.size() > 0) {
							missiles_v.remove(j);
							Explosion expl = new Explosion();
							expl.setX(enemis.get(i).getX()+16);
							expl.setY(enemis.get(i).getY()+32);
							enemis.remove(i);
							explosion.add(expl);
							score += 100;
						}						
					}
				}
			}
			
			for (int i=0; i < setufo.size(); i++) {
				Ufo ufo = (Ufo) setufo.get(i);
				Rectangle r1 = ufo.getBounds();
				
				if (!r1.intersects(screen)){
					setufo.remove(i);
				}
				
				else {
				
					for (int j=0; j < missiles_v.size(); j++) {
						Missile miss = missiles_v.get(j);
						Rectangle r2 = miss.getBounds();
						
						if (r1.intersects(r2) && setufo.size() > 0) {
							missiles_v.remove(j);
							Explosion expl = new Explosion();
							expl.setX(setufo.get(i).getX()+32);
							expl.setY(setufo.get(i).getY()+32);
							setufo.remove(i);
							explosion.add(expl);
							score += 100;
						}						
					}
				}
			}
			
			for (int i=0; i < rockets.size(); i++) {
				boolean destroy = false;
				Rocket rocket = (Rocket) rockets.get(i);
				Rectangle r1 = rocket.getBounds();
				
				if (!r1.intersects(screen)) {
					rockets.remove(i);
				}
				
				else {
					
					for (int j=0; j < missiles_v.size(); j++) {
						Missile miss = missiles_v.get(j);
						Rectangle r2 = miss.getBounds();
						
						if (r1.intersects(r2) && rockets.size() > 0 && destroy == false) {
							missiles_v.remove(j);
							Explosion expl = new Explosion();
							expl.setX(rockets.get(i).getX()-20);
							expl.setY(rockets.get(i).getY());
							
								for (int k=0; k < enemis.size(); k++) {
									Enemis ve = (Enemis) enemis.get(k);
									double d = Math.pow(Math.pow(ve.getX()-rocket.getX(), 2) + Math.pow(ve.getY()-rocket.getY(), 2), 0.5);
									if (d < 200){
										expl.setX(ve.getX()+16);
										expl.setY(ve.getY()+32);
										enemis.remove(k);
									}
								}
								
								for (int l=0; l < setufo.size(); l++) {
									Ufo ufo = (Ufo) setufo.get(l);
									double d = Math.pow(Math.pow(ufo.getX()-rocket.getX(), 2) + Math.pow(ufo.getY()-rocket.getY(), 2), 0.5);
									if (d < 40){
										expl.setX(ufo.getX()+32);
										expl.setY(ufo.getY()+32);
										setufo.remove(l);
									}
								}
							
							rockets.remove(i);
							destroy = true;
							explosion.add(expl);
							score += 50;
						}						
					}
					
				}
					
			}
		
	}

	public void keyPressed(KeyEvent e) {
		
		pressed.add(e.getKeyCode());
		
		if (e.getKeyCode() == KeyEvent.VK_LEFT) {
				dx=-0.9;
		}
		
		if (e.getKeyCode() == KeyEvent.VK_RIGHT){
			dx=0.9;
		}
		
		if (e.getKeyCode() == KeyEvent.VK_UP){
			dy=-0.9;
		}
		
		if (e.getKeyCode() == KeyEvent.VK_DOWN){
			dy=0.9;
		}
		
	}

	public void keyReleased(KeyEvent e) {
		
		pressed.remove(e.getKeyCode());
		
		if (e.getKeyCode() == KeyEvent.VK_LEFT && !pressed.contains(KeyEvent.VK_RIGHT)){
			dx=0;
		}
		
		else if (e.getKeyCode() == KeyEvent.VK_LEFT && pressed.contains(KeyEvent.VK_RIGHT)){
			dx=0.9;
		}
		
		if (e.getKeyCode() == KeyEvent.VK_RIGHT && !pressed.contains(KeyEvent.VK_LEFT)){
			dx=0;
		}
		
		else if (e.getKeyCode() == KeyEvent.VK_RIGHT && pressed.contains(KeyEvent.VK_LEFT)){
			dx=-0.9;
		}
		
		if (e.getKeyCode() == KeyEvent.VK_UP && !pressed.contains(KeyEvent.VK_DOWN)){
			dy=0;
		}
		
		else if (e.getKeyCode() == KeyEvent.VK_UP && pressed.contains(KeyEvent.VK_DOWN)){
			dy=0.9;
		}
		
		if (e.getKeyCode() == KeyEvent.VK_DOWN && !pressed.contains(KeyEvent.VK_UP)){
			dy=0;
		}
		
		else if (e.getKeyCode() == KeyEvent.VK_DOWN && pressed.contains(KeyEvent.VK_UP)){
			dy=-0.9;
		}

	}

	public void keyTyped(KeyEvent e) {
		
		if (e.getKeyChar() == 27) { 
			System.exit(0);
		}
		
	}
}
